/*
 * ProbabilisticBroadcast.cc
 *
 *  Created on: Nov 26, 2008
 *      Author: Damien Piguet, Dimitris Kotsakos, Jérôme Rousselot
 */

#include "AdaptiveProbabilisticBroadcast.h"

using std::map;
using std::pair;
using std::make_pair;
using std::endl;

Define_Module(AdaptiveProbabilisticBroadcast);

void AdaptiveProbabilisticBroadcast::initialize(int stage)
{
	ProbabilisticBroadcast::initialize(stage);

	if(stage == 1){

	    beta = 1.0;

        bvec.setName("Beta Vector");

	    timeInNeighboursTable = par("timeInNeighboursTable");
	}
}

void AdaptiveProbabilisticBroadcast::handleLowerMsg(cMessage* msg)
{
	ProbabilisticBroadcastPkt* m = check_and_cast<ProbabilisticBroadcastPkt*>(msg);
	// Update neighbors table before calling the method of the super class
	// because it may delete the message.
	updateNeighMap(m);
	ProbabilisticBroadcast::handleLowerMsg(msg);
}

void AdaptiveProbabilisticBroadcast::updateNeighMap(ProbabilisticBroadcastPkt* m)
{
	//find the network address of the node who sent the msg
	NeighborMap::key_type nodeAddress = m->getSrcAddr();
	//EV << "updateNeighMap(): neighAddress: " << nodeAddress << endl;

	//search for it in the "already-neighbors" map
	NeighborMap::iterator it = neighMap.find(nodeAddress);

	//if the node is a "new" neighbor
	if (it == neighMap.end()) {
		EV << "updateNeighMap(): The message came from a new neighbor! " << endl;

		// insert key value pair <node address, event> in neighborhood map.
		cMessage *removeEvent = new cMessage("removeEvent", NEIGHBOR_TIMER);

		// schedule the event to remove the entry after initT seconds
		scheduleAt(simTime()+timeInNeighboursTable, removeEvent);

		NeighborMap::value_type pairToInsert = make_pair(nodeAddress, removeEvent);
		pair<NeighborMap::iterator, bool> ret = neighMap.insert(pairToInsert);

		// set the context pointer to point to the integer that resembles to the address of
		// the node to be removed when the corresponding event occurs
		(ret.first)->second->setContextPointer((void*)(&(ret.first)->first));

	}
	//if the node is NOT a "new" neighbor update its timer
	else {
		EV << "updateNeighMap(): The message came from an already known neighbor! " << endl;
        //cancel the event that was scheduled to remove the entry for this neighbor
        cancelEvent(it->second);
        // Define a new event in order to remove the entry after initT seconds
        // Set the context pointer to point to the integer that resembles to the address of
        // the node to be removed when the corresponding event occurs
		it->second->setContextPointer((void*)(&it->first));

		scheduleAt(simTime()+timeInNeighboursTable, it->second);
	}
	updateBeta();
}

void AdaptiveProbabilisticBroadcast::handleSelfMsg(cMessage* msg)
{
	if (msg->getKind() == NEIGHBOR_TIMER) {
		const NeighborMap::key_type& node = *static_cast<NeighborMap::key_type*>( msg->getContextPointer() );
		EV << "handleSelfMsg(): Remove node "<< node <<" from NeighMap!" << endl;
		NeighborMap::iterator it = neighMap.find(node);
		cancelAndDelete(neighMap.find(it->first)->second);
		neighMap.erase(it);
		updateBeta();
	}
	else {
		ProbabilisticBroadcast::handleSelfMsg(msg);
	}
}

void AdaptiveProbabilisticBroadcast::updateBeta()
{
	int k = neighMap.size();

	// those values are derived from the simulations
	// with the non-adaptive protocol.
	if (k < 4)
		beta = 1.0;
	else if (k < 6)
		beta = 0.9;
	else if (k < 8)
		beta = 0.8;
	else if (k < 10)
		beta = 0.7;
	else if (k < 12)
		beta = 0.6;
	else if (k < 14)
		beta = 0.5;
	else if (k < 16)
		beta = 0.4;
	else if (k < 18)
		beta = 0.3;
	else if (k < 20)
		beta = 0.2;
	else
		beta = 0.1;
	if(trace) {
		bvec.record(beta);
	}
}

